package com.hontech.dapapp.utils

import com.hontech.dapapp.app.AppContext
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.decodeFromByteArray
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.concurrent.TimeUnit


@Serializable
data class Pro (
    val id: Long,
    val name: String,
    val description: String
)

@Serializable
data class Hex (
    val id: Long,
    val name: String,
    val version: String,
    val description: String,

    @SerialName("create_timestamp")
    val createTimestamp: Long,
    val target: String,
    val size: Long
)

@Serializable
data class ErrInfo (
    @SerialName("err_code")
    val errCode: Int,
    @SerialName("err_msg")
    val errMsg: String
)

val httpClient = OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(10, TimeUnit.SECONDS)
    .build()

private const val BASE_URL = "http://local.hontech-rdcenter.com:33340/api"

private fun getUrl(url: String) = "${BASE_URL}${url}"


@OptIn(ExperimentalSerializationApi::class)
private inline fun<reified T> checkResp(resp: Response): T {
    if (resp.code != 200) {
        throw IOException("status fail:${resp.message}")
    }
    val respType = resp.headers["resp"] ?: throw IOException("no resp head")
    if (respType == "ok") {
        return Cbor.decodeFromByteArray<T>(resp.body?.bytes() ?: throw IOException("no body"))
    }
    val errInfo = Cbor.decodeFromByteArray<ErrInfo>(resp.body?.bytes() ?: throw IOException("no body"))
    throw IOException(errInfo.errMsg)
}

@OptIn(ExperimentalSerializationApi::class)
private fun checkResp2(resp: Response): ByteArray {
    if (resp.code != 200) {
        throw IOException("status fail:${resp.message}")
    }
    val respType = resp.headers["resp"] ?: throw IOException("no resp head")
    if (respType == "ok") {
        return resp.body?.bytes() ?: throw IOException("no body")
    }
    val errInfo = Cbor.decodeFromByteArray<ErrInfo>(resp.body?.bytes() ?: throw IOException("no body"))
    throw IOException(errInfo.errMsg)
}

private suspend inline fun<reified T> doGet(url: String): T {
    return runIO {
        val req = Request.Builder().url(getUrl(url)).get().build()
        val resp = httpClient.newCall(req).execute()
        checkResp<T>(resp)
    }
}


suspend fun queryPro(): Array<Pro> {
    return doGet("/pro/query")
}


suspend fun queryHex(proId: Long): Array<Hex> {
    return doGet("/hex/query?pro_id=${proId}")
}

suspend fun download(id: Long): String {
    return runIO {
        val req = Request.Builder().url(getUrl("/hex/get?id=${id}")).get().build()
        val resp = httpClient.newCall(req).execute()
        val body = checkResp2(resp)

        val file = File(AppContext.filesDir, "firm.hex")
        val out = FileOutputStream(file)
        out.use {
            out.write(body)
        }

        file.path
    }
}














